#include "DIVA_Manager.h"
#include "ubrvm_laser.h"
#include "vmLibrary.h"

#define COLOR_MODULATE_PARAM_INDEX 1
// @@@@
/// constructor
//Name           : hyt
//Update Date    : 08/10/26
//Update History :
//				(1) VL_createEntity 必須給 meshname,material可給可不給,若想自行命名vm的開頭,則可以
//                   再加第三個參數 string specialhead
//              (2) VL_regBoudingBox 則需要 vm的entity 
//              (3) 由programmer自行決定node內容
//              (4) 若要在vm任何一個位置顯示文字,首先呼叫VL_createVMText(你想顯示的文字,文字node的開頭name)
//                  再來是呼叫VL_createTextNode(vm文字位置)
//              (5) 設定vm node顏色則呼叫VL_setEntityColor(vm entity , Vector4(colorvalue))來設定
ubrvm_laser::ubrvm_laser(xParameterPack xpp):ReferenceVM(xpp){

	int default_port_number = vmLibrary::instance().get_vm_default_input_parameters().size();

	// reference vm is designed based on a proxy pattern
	// first, a reference vm has its own body
	// second, it must points to a vm (called pointed vm)
	// however, this pointed vm can be any vm and changed from time to time
	// so, a fixed vm passed to the constructor's parameters would not work.
	// so, a pragmatic way is to allowed user connect wop to a variable
	// in xNodeType_VM::createMappedObject(), we scan for hidden vm inport immediately
	// behind the wop. If there is a hidden vm inport, we use the wop to create a dummy vm
	// and feed this dummy as the parameter of the vm.  This dummy vm is designed based
	// on proxy pattern. The dummy vm is responsible for evaluating the wop value, search the 
	// represented VM and redirect the events and action to the vm.


	assert(xpp.no == default_port_number+3);
	_pointedVM = xpp.paras[default_port_number+1].val_vm ;  // @@@@ this _pointedVM is actually a dummyVM
	_proxyVM = (dummyVM *) _pointedVM ; // @@@@ cast it to dummyVM to use the method  isPointedNULL()
	_shapeVM = xpp.paras[default_port_number+2].val_vm ; // this is the VM which is used to 

	_clicked = false ;
		
	VL_addVMAnimation();
	_track = setupTrailLights(this->getWorldPosition(),this->getWorldPosition());///add by James

	init_default_parameters(); // this line must be added at the end of each VM constructor
}

/// destructor
ubrvm_laser::~ubrvm_laser(){
}
void ubrvm_laser::load_3Dresources() {

		Ogre::Vector3 pos=_shapeVM->getPosition(); 
		Ogre::SceneNode *parent = _shapeVM->getParentSceneNode() ;
		Ogre::SceneNode *s = _shapeVM->getSceneNode();
		parent->removeChild(s);
		_SceneNode->addChild(s);
		_shapeVM->setParentSceneNode(_SceneNode);
		_shapeVM->setPosition(pos);

}
void ubrvm_laser::reg_event_entity() {

	// register the relation of the entity and vm in diva manager
	// When this entity is clicked, mouse/keyboard VM will be passed to this VM
	
	// In this VM, we do not have entity here
}
void ubrvm_laser::set_default_values() {

	_vm_rx_val = 0 ;
	_vm_ry_val = 0 ;
	_vm_rz_val = 0 ;

	Ogre::Vector3 sz = this->getActualSize();
	_vm_init_sizex = sz.x ;
	_vm_init_sizey = sz.y ;
	_vm_init_sizez = sz.z ;

	_vm_sizex_val = sz.x ;
	_vm_sizey_val = sz.y ;
	_vm_sizez_val = sz.z ;

	_vm_sizexscale_val = 1.0 ;
	_vm_sizeyscale_val = 1.0 ;
	_vm_sizezscale_val = 1.0 ;

	_vm_r_val = 0.3;  // white color but with transparency 0.1
	_vm_g_val = 0.3;
	_vm_b_val = 0.3;
	_vm_transparency_val = 1.0 ;

	_vm_yaw_val = 0 ;
	_vm_pitch_val = 0 ;
	_vm_roll_val = 0 ;

}

void ubrvm_laser::init_private_attrs_started() {
	
}
void ubrvm_laser::init_color_and_transparency() {
	// we do not have entity in this VM
	// so we need to do nothing for color and transparency

}
void ubrvm_laser::update_color_and_transparency() {
	init_color_and_transparency();
}
void ubrvm_laser::VMValueUpdated() {

	/* the  WOP_ref_entry is changed. So, there is a new VM to pointed to.  
	     We clear the _proxyVM's pointed VM so that when we call _proxyVM->getWorldPosition()
		 it will initiate a sequence of unfoldref()
    */	
	_proxyVM->clearPointedVM();
	_animState->setEnabled(false);
	disableVMAnimation();

	
}

void ubrvm_laser::VMAnimation(const Ogre::FrameEvent& evt) {
	if (_visible == false)  return ;
	if (!_proxyVM->hasNULLvalue()) { // @@@@@

		Ogre::Vector3 start = getWorldPosition() ;
		Ogre::Vector3 end = _proxyVM->getWorldPosition();
		///add by James for update the track
		if (_proxyVM != NULL){
			_track->getNodeKeyFrame(0)->setTranslate(start);
			_track->getNodeKeyFrame(1)->setTranslate(end);
		}
		_animState->addTime(evt.timeSinceLastFrame);
	}
}
void ubrvm_laser::VMSetVisible(bool vis) {
	if (_visible != vis) {
		  _visible = vis ;
        _SceneNode->setVisible(vis);
		_shapeVM->VMSetVisible(vis);
	}	
}
void ubrvm_laser::VMPicked(Ogre::Real x, Ogre::Real y, Ogre::Real z) {

	enableVMAnimation();
	_animState->setEnabled(true);
	if (! _proxyVM->hasNULLvalue()) { //@@@@ 
		_shapeVM->setColorandTransparency(Ogre::Vector4(1.0,1.0,1.0, 1.0f));
		// give the VM a white color
	
		Ogre::Vector3 start = getWorldPosition() ;
		Ogre::Vector3 end = _proxyVM->getWorldPosition();

		///add by James for update the track
		if (_proxyVM != NULL){
			_track->getNodeKeyFrame(0)->setTranslate(start);
			_track->getNodeKeyFrame(1)->setTranslate(end);
		}
	} else {  //@@@@
		// give the VM a black color 
		_shapeVM->setColorandTransparency(Ogre::Vector4(0.6f, 0.2f, 0.2f, 1.0f));
		// VL_setEntityColor(_ent,);		
	}
	
}
/** we must override this method because this vm has no entity 
    Its entity is at _shapeVM 
*/
bool ubrvm_laser::isSubComponent(DIVA_VM *vm) {
	// if _shapevm is an entity vm, the test is straightforward
	// if _shapevm is a composite vm, the test is passed to the composite vm
	// to recurively check if it is a subcomponent
	return _shapeVM->isSubComponent(vm);
}
void ubrvm_laser::scaleBodyToAbsSize(Ogre::Vector3 v){
	setBodyScale(Ogre::Vector3(v.x/_vm_init_sizex,
		                 v.y/_vm_init_sizey,
						 v.z/_vm_init_sizez));
}
void ubrvm_laser::setBodyScale(Ogre::Vector3 scale) {
	_SceneNode->setScale(scale);
}
bool ubrvm_laser::isBodyScaleWrtSceneNode() { return true ; }

Ogre::Vector3 ubrvm_laser::getOriginalBodySize() {
	return Ogre::Vector3(_vm_init_sizex, _vm_init_sizey, _vm_init_sizez) ;
}

Ogre::Vector3 ubrvm_laser::getActualSize() {
	 Ogre::Vector3 size=_shapeVM ->getActualSize();
	 return size ;
}
Ogre::Vector3 ubrvm_laser::getBodyScale() {
	return _SceneNode->getScale();
}
Ogre::NodeAnimationTrack* ubrvm_laser::setupTrailLights(Ogre::Vector3 start,Ogre::Vector3 end)
{
	static int num = 0;
	num++;
	Ogre::String number = intToString(num);
	Ogre::String name = "ShouldNotClicked";
	name = name + number;
	Ogre::NameValuePairList pairList;
	pairList["numberOfChains"] = "2";
	pairList["maxElements"] = "80";
	Ogre::RibbonTrail* trail = static_cast<Ogre::RibbonTrail*>(
		DIVA_Manager::getInstance()->getSceneManager()->createMovableObject(name, "RibbonTrail", &pairList));
	trail->setMaterialName("Examples/LightRibbonTrail");
	trail->setTrailLength(4000);


	DIVA_Manager::getInstance()->getSceneManager()->getRootSceneNode()->createChildSceneNode()->attachObject(trail);
	// Create 3 nodes for trail to follow
	Ogre::SceneNode* animNode = DIVA_Manager::getInstance()->getSceneManager()->getRootSceneNode()->createChildSceneNode();

	animNode->setPosition(start);

	Ogre::Animation* anim = DIVA_Manager::getInstance()->getSceneManager()->createAnimation("an"+name , 4);//表示這個動畫是 4 秒
	anim->setInterpolationMode(Ogre::Animation::IM_SPLINE);
	Ogre::NodeAnimationTrack* track = anim->createNodeTrack(1, animNode);

	Ogre::TransformKeyFrame* kf = track->createNodeKeyFrame(0);

	kf->setTranslate(start);

	kf = track->createNodeKeyFrame(4);
	kf->setTranslate(end);


	_animState= DIVA_Manager::getInstance()->getSceneManager()->createAnimationState("an"+name);
	_animState->setLoop(true);
	_animState->setEnabled(true);

	trail->setInitialColour(0, 1.0, 0.8, 0);
	trail->setColourChange(0, 0.5, 0.5, 0.5, 0.5);
	trail->setInitialWidth(0, 5);
	trail->addNode(animNode);
	//AxisAlignedBox box = trail->getBoundingBox();
	//box.scale(Vector3(0,0,0));

	return track;
}
